package org.simplextensions.registry;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.simplextensions.annotations.Extension;

@Extension
public class JNDIServiceLocator implements IServiceLocator {

	private static final String CONTAINER2 = "container";

	private Map<String, Properties> jndiPropertiesMap = new HashMap<String, Properties>();

	public enum Container {
		JBossAS, OpenEJB, Google
	}

	private Properties defaults = new Properties();
	{
		defaults.setProperty(CONTAINER2, Container.Google.name());
	}

	public <T> T getService(IServiceRegistry serviceRegistry, Class<T> serviceInterface) {
		String resourceName = "./" + serviceInterface.getPackage().getName().replace('.', '/');
		Properties properties = getProperties(resourceName);

		InitialContext initialContext;
		try {
			if (properties.contains(Context.INITIAL_CONTEXT_FACTORY))
				initialContext = new InitialContext(properties);
			else
				initialContext = new InitialContext();
			
			String serviceName = getServiceName(serviceInterface, properties);
			return (T) initialContext.lookup(serviceName);
		} catch (NamingException e) {
			throw new RuntimeException(e);
		}
	}

	private String getServiceName(Class<?> clazz, Properties properties) {
		String property = properties.getProperty(CONTAINER2);
		if (Container.Google.name().equals(property)) {
			return clazz.getSimpleName();
		} else if (Container.JBossAS.equals(property)) {

			String type = "remote";

			Object annotation;
			try {
				annotation = clazz.getAnnotation((Class<Annotation>) Class.forName("javax.ejb.Local"));

				if (annotation != null)
					type = "local";
				return properties.get("ear.name") + "/" + clazz.getSimpleName().replace("Local", "Bean").replace("Remote", "Bean") + type;
			} catch (ClassNotFoundException e) {
				throw new RuntimeException(e);
			}
		} else {
			throw new RuntimeException(property + " is unknown server type");
		}
	}

	public Properties getProperties(String resourceName) {
		Properties properties = jndiPropertiesMap.get(resourceName);
		if (properties != null)
			return properties;

		
		try {
			URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName + "/jndi.properties");

			if (url != null) {
				jndiPropertiesMap.put(resourceName, properties = new Properties(defaults));

				FileInputStream inStream = new FileInputStream(new File(url.toURI()));
				properties = new Properties(defaults);
				properties.load(inStream);
				inStream.close();
				return properties;
			} else if (!".".equals(resourceName)) {
				return getProperties(resourceName.substring(0, resourceName.lastIndexOf("/")));
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (URISyntaxException e) {
			throw new RuntimeException(e);
		}
		return new Properties(defaults);
	}

	public void start(IServiceRegistry serviceRegistry) {

	}

	public void stop(IServiceRegistry serviceRegistry) {

	}

}
